#ifndef StreamBuf_First
#define StreamBuf_First
#ifdef __GNUG__
#pragma interface
#endif

#include "Types.h"
#include "ET_stdio.h"

#ifndef BUFSIZE
#       define BUFSIZE 4096
#endif

#define zapeof(c) ((c) & 0377)

//---- StreamBuf ---------------------------------------------------------------
//     an input/output buffer for streams

class StreamBuf {
public:
	StreamBuf(int size= BUFSIZE, const char *p= 0, int count= 0, bool alloc= FALSE);
	virtual ~StreamBuf();

	void Finish();
	void SetBaseStream(StreamBuf *s);
	StreamBuf *GetBaseStream();

	// supply an area for a buffer.
	// The "count" parameter allows the buffer to start in non-empty.
	StreamBuf *setbuf(const char *p, int len, int count= 0, bool alloc= FALSE);

	// return size of buffer
	u_long size();
		
	// Empty a buffer. Return EOF on error; 0 on success
	virtual int overflow(int c= EOF);

	// Fill a buffer. Return EOF on error or end of input; next character on success
	virtual int underflow();

	virtual int Underflow(u_char *bp, int size);
	virtual int Overflow(u_char *bp, int size);
	virtual void Close();
	virtual long Seek(long pos, int whence);
	int seek(long pos, bool relative= FALSE);
	long tell();

	char *Base();
	int sgetc();    // get the current character
	int sbumpc();   // get the current character and advance to the next character
	int snextc();   // get the next character
	void stossc();  // advance to the next character

	// Return a character to the buffer (ala lookahead 1).  Since
	// the user may be "playing games" the character might be
	// different than the last one returned by sgetc or snextc.
	// been extracted, nothing will be put back.
	// Putting back an EOF is DANGEROUS.
	void sputbackc(char c);

	// put a character into the buffer
	int sputc(int c= EOF);

	// put n characters into the buffer
	int sputn(const char *buf, int n);

	// get n characters from the buffer
	int sgetn(char *buf, int n);

	int salloc(char **buf, int size);

protected:
	StreamBuf *sb;  // base streambuf
	char *base;     // pointer to beginning of buffer
	char *ptr;      // pointer to next free byte
	char *gptr;     // pointer to next free byte
	char *eptr;     // pointer to first byte following buffer
	bool alloc;     // true if buffer is allocated using "new"
	long fpos;
};

inline u_long StreamBuf::size()
	{ return (u_long) (eptr-base); }
inline long StreamBuf::tell()
	{ return fpos + (long) (ptr-base); }
inline char *StreamBuf::Base()
	{ return base; }
inline int StreamBuf::sgetc()
	{ return (ptr >= gptr) ? underflow() : zapeof(*ptr); }
inline int StreamBuf::sbumpc()
	{ return (ptr >= gptr) ? underflow() : zapeof(*ptr++); }
inline int StreamBuf::snextc()
	{ return (ptr >= (gptr-1)) ? underflow() : zapeof(*++ptr); }
inline void StreamBuf::stossc()            // advance to the next character
	{ if (ptr++ >= gptr) underflow(); }
inline int StreamBuf::sputc(int c)
	{ return (eptr <= ptr) ? overflow(zapeof(c)) : (*ptr++= zapeof(c)); }

#endif
